package cn.javacart.jopencart.library.cart;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cn.javacart.jopencart.kit.SetKit;
import cn.javacart.jopencart.model.TaxRate;

import com.jfinal.aop.Duang;

/**
 * 
 * @author farmer
 *
 */
public class TaxService {
	
	public final static TaxService ME = Duang.duang(TaxService.class);
	
	static ThreadLocal<Map<Integer, Map<Integer, TaxRate>>> threadLocal = new ThreadLocal<Map<Integer,Map<Integer,TaxRate>>>();
	
	public static void reset(){
		threadLocal.set(null);
	}
	
	/**
	 * 设置配送地址的税
	 * @param countryId
	 * @param zoneId
	 */
	public void setShippingAddress(Integer countryId, Integer zoneId){
		String sql = "SELECT\n" + 
				"	tr1.tax_class_id,\n" + 
				"	tr2.tax_rate_id,\n" + 
				"	tr2.name,\n" + 
				"	tr2.rate,\n" + 
				"	tr2.type,\n" + 
				"	tr1.priority\n" + 
				"FROM\n" + 
				"	joc_tax_rule tr1\n" + 
				"LEFT JOIN joc_tax_rate tr2 ON\n" + 
				"	(\n" + 
				"		tr1.tax_rate_id = tr2.tax_rate_id\n" + 
				"	)\n" + 
				"INNER JOIN joc_tax_rate_to_customer_group tr2cg ON\n" + 
				"	(\n" + 
				"		tr2.tax_rate_id = tr2cg.tax_rate_id\n" + 
				"	)\n" + 
				"LEFT JOIN joc_zone_to_geo_zone z2gz ON\n" + 
				"	(\n" + 
				"		tr2.geo_zone_id = z2gz.geo_zone_id\n" + 
				"	)\n" + 
				"LEFT JOIN joc_geo_zone gz ON\n" + 
				"	(\n" + 
				"		tr2.geo_zone_id = gz.geo_zone_id\n" + 
				"	)\n" + 
				"WHERE\n" + 
				"	tr1.based = 'shipping'\n" + 
				"	AND tr2cg.customer_group_id = '1'\n" + 
				"	AND z2gz.country_id = ?\n" + 
				"	AND(\n" + 
				"		z2gz.zone_id = '0'\n" + 
				"		OR z2gz.zone_id = ?\n" + 
				"	)\n" + 
				"ORDER BY\n" + 
				"	tr1.priority ASC";
		List<TaxRate> taxRates = TaxRate.ME.find(sql,countryId,zoneId);
		Map<Integer, Map<Integer, TaxRate>> taxClassIdMap = threadLocal.get();
		if(taxClassIdMap == null){
			taxClassIdMap = new HashMap<Integer, Map<Integer,TaxRate>>();
			threadLocal.set(taxClassIdMap);
		}
		for (TaxRate taxRate : taxRates) {
			Map<Integer, TaxRate> taxRateIdMap = taxClassIdMap.get(taxRate.getInt("tax_class_id"));
			if(taxRateIdMap == null){
				taxRateIdMap = new HashMap<Integer, TaxRate>();
			}
			taxRateIdMap.put(taxRate.getInt("tax_rate_id"), taxRate);
			taxClassIdMap.put(taxRate.getInt("tax_class_id"), taxRateIdMap);
		}
	}
	
	/**
	 * 设置支付地址的税
	 * @param countryId
	 * @param zoneId
	 */
	public void setPaymentAddress(Integer countryId, Integer zoneId){
		String sql = "SELECT\n" + 
				"	tr1.tax_class_id,\n" + 
				"	tr2.tax_rate_id,\n" + 
				"	tr2.name,\n" + 
				"	tr2.rate,\n" + 
				"	tr2.type,\n" + 
				"	tr1.priority\n" + 
				"FROM\n" + 
				"	joc_tax_rule tr1\n" + 
				"LEFT JOIN joc_tax_rate tr2 ON\n" + 
				"	(\n" + 
				"		tr1.tax_rate_id = tr2.tax_rate_id\n" + 
				"	)\n" + 
				"INNER JOIN joc_tax_rate_to_customer_group tr2cg ON\n" + 
				"	(\n" + 
				"		tr2.tax_rate_id = tr2cg.tax_rate_id\n" + 
				"	)\n" + 
				"LEFT JOIN joc_zone_to_geo_zone z2gz ON\n" + 
				"	(\n" + 
				"		tr2.geo_zone_id = z2gz.geo_zone_id\n" + 
				"	)\n" + 
				"LEFT JOIN joc_geo_zone gz ON\n" + 
				"	(\n" + 
				"		tr2.geo_zone_id = gz.geo_zone_id\n" + 
				"	)\n" + 
				"WHERE\n" + 
				"	tr1.based = 'payment'\n" + 
				"	AND tr2cg.customer_group_id = '1'\n" + 
				"	AND z2gz.country_id = ?\n" + 
				"	AND(\n" + 
				"		z2gz.zone_id = '0'\n" + 
				"		OR z2gz.zone_id = ?\n" + 
				"	)\n" + 
				"ORDER BY\n" + 
				"	tr1.priority ASC";
		List<TaxRate> taxRates = TaxRate.ME.find(sql,countryId,zoneId);
		Map<Integer, Map<Integer, TaxRate>> taxClassIdMap = threadLocal.get();
		if(taxClassIdMap == null){
			taxClassIdMap = new HashMap<Integer, Map<Integer,TaxRate>>();
			threadLocal.set(taxClassIdMap);
		}
		for (TaxRate taxRate : taxRates) {
			Map<Integer, TaxRate> taxRateIdMap = taxClassIdMap.get(taxRate.getInt("tax_class_id"));
			if(taxRateIdMap == null){
				taxRateIdMap = new HashMap<Integer, TaxRate>();
			}
			taxRateIdMap.put(taxRate.getInt("tax_rate_id"), taxRate);
			taxClassIdMap.put(taxRate.getInt("tax_class_id"), taxRateIdMap);
		}
	}
	
	/**
	 * 设置商店地址的税
	 * @param countryId
	 * @param zoneId
	 */
	public void setStoreAddress(Integer countryId, Integer zoneId){
		String sql = "SELECT\n" + 
				"	tr1.tax_class_id,\n" + 
				"	tr2.tax_rate_id,\n" + 
				"	tr2.name,\n" + 
				"	tr2.rate,\n" + 
				"	tr2.type,\n" + 
				"	tr1.priority\n" + 
				"FROM\n" + 
				"	joc_tax_rule tr1\n" + 
				"LEFT JOIN joc_tax_rate tr2 ON\n" + 
				"	(\n" + 
				"		tr1.tax_rate_id = tr2.tax_rate_id\n" + 
				"	)\n" + 
				"INNER JOIN joc_tax_rate_to_customer_group tr2cg ON\n" + 
				"	(\n" + 
				"		tr2.tax_rate_id = tr2cg.tax_rate_id\n" + 
				"	)\n" + 
				"LEFT JOIN joc_zone_to_geo_zone z2gz ON\n" + 
				"	(\n" + 
				"		tr2.geo_zone_id = z2gz.geo_zone_id\n" + 
				"	)\n" + 
				"LEFT JOIN joc_geo_zone gz ON\n" + 
				"	(\n" + 
				"		tr2.geo_zone_id = gz.geo_zone_id\n" + 
				"	)\n" + 
				"WHERE\n" + 
				"	tr1.based = 'store'\n" + 
				"	AND tr2cg.customer_group_id = '1'\n" + 
				"	AND z2gz.country_id = ?\n" + 
				"	AND(\n" + 
				"		z2gz.zone_id = '0'\n" + 
				"		OR z2gz.zone_id = ?\n" + 
				"	)\n" + 
				"ORDER BY\n" + 
				"	tr1.priority ASC";
		List<TaxRate> taxRates = TaxRate.ME.find(sql,countryId,zoneId);
		Map<Integer, Map<Integer, TaxRate>> taxClassIdMap = threadLocal.get();
		if(taxClassIdMap == null){
			taxClassIdMap = new HashMap<Integer, Map<Integer,TaxRate>>();
			threadLocal.set(taxClassIdMap);
		}
		for (TaxRate taxRate : taxRates) {
			Map<Integer, TaxRate> taxRateIdMap = taxClassIdMap.get(taxRate.getInt("tax_class_id"));
			if(taxRateIdMap == null){
				taxRateIdMap = new HashMap<Integer, TaxRate>();
			}
			taxRateIdMap.put(taxRate.getInt("tax_rate_id"), taxRate);
			taxClassIdMap.put(taxRate.getInt("tax_class_id"), taxRateIdMap);
		}
	}
	
	/**
	 * 
	 * @param value
	 * @param taxClassId
	 * @param calculate
	 * @return
	 */
	public BigDecimal calculate(BigDecimal value ,Integer taxClassId , String calculate){
		if(taxClassId != null && SetKit.isset(calculate)){
			BigDecimal amount = new BigDecimal(0);
			Map<Integer, TaxRate> rates = getRates(value, taxClassId);
			for (Map.Entry<Integer, TaxRate> entry : rates.entrySet()) {
				TaxRate taxRate = entry.getValue();
				if (!"P".equals(calculate) && !"F".equals(calculate)) {
					amount = amount.add(taxRate.getBigDecimal("amount"));
				} else if (calculate.equals(taxRate.getStr("type"))) {
					amount = amount.add(taxRate.getBigDecimal("amount"));
				}
			}
			return value.add(amount);
		}
		return value;
	}
	
	
	/**
	 * 获取税
	 * @param value
	 * @param taxClassId
	 * @return
	 */
	public BigDecimal getTax(BigDecimal value, Integer taxClassId) {
		BigDecimal amount = new BigDecimal(0);
		Map<Integer, TaxRate> rates = getRates(value, taxClassId);
		for (Map.Entry<Integer, TaxRate> entry : rates.entrySet()) {
			amount = amount.add(entry.getValue().getBigDecimal("amount"));
		}
		return amount;
	}
	
	/**
	 * 获取税率名称
	 * @param taxRateId
	 * @return
	 */
	public String getRateName(Integer taxRateId){
		TaxRate taxRate = TaxRate.ME.findById(taxRateId);
		return taxRate == null ? null : taxRate.getStr("name");
	}	
	/**
	 * 获取税率
	 * @param value
	 * @param taxClassId
	 * @return
	 */
	public Map<Integer, TaxRate> getRates(BigDecimal value , Integer taxClassId){
		Map<Integer, TaxRate> taxRateMap = new HashMap<Integer, TaxRate>();
		if(threadLocal.get()!= null && threadLocal.get().get(taxClassId) != null){
			Map<Integer, TaxRate> taxRateIdMap = threadLocal.get().get(taxClassId);
			for(Map.Entry<Integer, TaxRate> entry : taxRateIdMap.entrySet()){
				TaxRate taxRate = entry.getValue();
				TaxRate taxRateHasAmount = taxRateMap.get(taxRate.getInt("tax_rate_id"));
				BigDecimal amount = new BigDecimal(0);
				if(taxRateHasAmount != null){
					amount = taxRateHasAmount.getBigDecimal("amount");
				}
				if ("F".equals(taxRate.getStr("type"))) {
					amount = amount.add(taxRate.getBigDecimal("rate"));
				} else if ("P".equals(taxRate.getStr("type"))) {
					amount = amount.add(value.divide(new BigDecimal(100)).multiply(taxRate.getBigDecimal("rate")));
				}
				taxRate.put("amount", amount);
				taxRateMap.put(taxRate.getInt("tax_rate_id"), taxRate);
			}
		}
		return taxRateMap;
	}
	
}